package algoritmo;

import java.awt.Point;

public class Constantes
{
	public static final int PARADO = 0;
	public static final int CIMA = 1;
	public static final int BAIXO = 2;
	public static final int DIREITA = 3;
	public static final int ESQUERDA = 4;
	
	public static final int VISAO_CIMA = 7;
	public static final int VISAO_BAIXO = 16;
	public static final int VISAO_ESQUERDA = 11;
	public static final int VISAO_DIREITA = 12;
	
	
	public static final int VISAO_SEMVISAO = -2;
	public static final int VISAO_DESCONHECIDO = -3;
	public static final int VISAO_INATINGIVEL = -4;
	public static final int VISAO_VAZIO = 0;
	public static final int VISAO_EXTERNO = -1;
	public static final int VISAO_PAREDE = 1;
	public static final int VISAO_BANCO = 3;
	public static final int VISAO_MOEDA = 4;
	public static final int VISAO_PASTILHA = 5;	
	public static final int[] VISAO_LADRAO = { 200, 210, 220, 230 };
	public static final int[] VISAO_POUPADOR = { 100, 110 };
	
	public static final int CHEIRO_TAMLEMBRANCA = 11;
	/**
	 * At� quantas rodadas lembramos do cheiro
	 */
	public static final int CHEIRO_CHEIROLIMITE = 5;
	public static final int CHEIRO_SEMCHEIRO = 0;
	
	public static final int LEMBRANCA_LIMITE_LADRAO = 4;	
	public static final int LEMBRANCA_LIMITE_POUPADOR = 2; // cuidado, nao aumentar esse valor alem do campo de visao (2)
	public static final int LEMBRANCA_LIMITE_INATINGIVEL = 20;
	
	/**
	 * Qual número máximo de loops que devemos esperar antes de sair correndo sem pensar em mais nada.
	 */
	public static final int HISTORICO_LOOP_MAX = 3;
	
	/**
	 * Número de rodadas que vamos pensar que somos como o Chuck Noris - isto é, ngm pode com a gente.
	 * Basicamente isso será usado quando precisamos fingir que não podemos ser roubados porque ficamos encurralados
	 * pelo ladrão em um loop.
	 */
	public static final int CHUCK_NORIS_TICKS = 5;
	
	/**
	 * Menor distancia de manhattan aceitavel do ladrao
	 */
	public static final int MIN_DIST_LADRAO = 2;
	
	/**
	 * Numero de ticks que devemos esperar antes de começar o berserk, isso eh, sair pegando moedas desenfreadamente!
	 * Se queremos berserk após jogar 100 turnos, entao 100 eh o valor a colocar aqui!
	 */
	public static final int THIS_IS_SPARTAAAAAA = 650;	
	
	/**
	 * Quantas moedas precisamos para estarmos ricos
	 */
	public static final int RICO = 20;
	
	public static final int MUNDO_TAM = 30;
	public static final int HISTORICO_POSICAO_LEN = 80;
	public static final int BUSCA_PROFUNDIDADE = 6;
	
	
	/*
	 * Retorna true se a célula possui um ladrão.
	 */
	public static boolean contemLadrao(int valorCelula)
	{
		for (int i = 0; i < VISAO_LADRAO.length; i++)
			if(VISAO_LADRAO[i] == valorCelula) return true;
		return false;
	}
	
	/*
	 * Retorna true se a célula possui um popuador.
	 */
	public static boolean contemPupador(int valorCelula)
	{
		for (int i = 0; i < VISAO_POUPADOR.length; i++)
			if(VISAO_POUPADOR[i] == valorCelula) return true;
		return false;
	}
	
	public static int manhattan(Point a, Point b)
	{
		return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
	}	
	
	/**
	 * Retorna true se o ponto eh valido
	 */
	public static boolean isValidPoint(Point p, int numeroMoedas, int[][] mundo)
	{
		// se pontos estao fora do mundo sao automaticamente invalidos
		if (p.x < 0 || p.y < 0 || p.x >= Constantes.MUNDO_TAM || p.y >= Constantes.MUNDO_TAM)
			return false;
		
		int val = mundo[p.y][p.x];
		
		// ponto eh valido se nao eh uma parede, mundo externo ou se o ladrao estah nele
		return
			val != Constantes.VISAO_PAREDE     &&
			val != Constantes.VISAO_EXTERNO    &&
			val != Constantes.VISAO_BANCO      &&
			val != Constantes.VISAO_INATINGIVEL &&
			(
				val != Constantes.VISAO_PASTILHA	// pastilhas sao validas apens se tivermos mais de 5 moedas
				|| numeroMoedas >= 5
			 )								   &&
			!Constantes.contemPupador(val)     &&
			!Constantes.contemLadrao(val); 
	}	
	
	/**
	 * Verifica se um dado quadro a uma certa distância da nossa posição é seguro.
	 * @param numeroMoedas Número de moedas que temos
	 * @param distanciaMovimento Distância da minha posição até o quadro analisado.
	 * @param distanciaLadrao Distância do ladrão até a posição analisada.
	 * @return TRUE se podemos ir para o quadro sem que haja chance de sermos roubados
	 */
	public static boolean distanciaSegura(int numeroMoedas, int distanciaMovimento, int distanciaLadrao)
	{
		// apenas queremos uma distancia segura se tivermos moedas
		if (numeroMoedas > 0)
		{
			int diffDistancia = distanciaLadrao - distanciaMovimento;
			// se o ladrao conseguir chegar um quadro antes do analisado
			// ou no proprio quadro antes da gente, entao precisamos 
			// evitamos caminho
			if (diffDistancia <= 1)
			{
				// nao eh uma posicao boa, ir para lá significa ser roubado!
				return false;
			}
		}
		
		return true;
	}
	
	/*
	 * Retorna qual acao tomar para ir da posicao atual a posicao destino.
	 * Esse método decide de forma simples para onde ir. Idealmente deve-se ter posicaoDestino e atual contiguas
	 * Nao eh aplicada qualquer logica de caminho
	 */
	public static int tomarAcao(Point pos, Point proximoQuadro)
	{
		int acao;
		//tentamos ir o destino
		if (proximoQuadro.x > pos.x)
			acao = Constantes.DIREITA;
		else if (proximoQuadro.x < pos.x)
			acao = Constantes.ESQUERDA;
		else if (proximoQuadro.y > pos.y)
			acao = Constantes.BAIXO;
		else if (proximoQuadro.y < pos.y)
			acao = Constantes.CIMA;
		else
			acao = Constantes.PARADO;
		
		return acao;
	}
}